perm filename XX[P,JRA] blob sn#052567 filedate 1973-08-07 generic text, type T, neo UTF8
COMMENT ⊗   VALID 00004 PAGES 
RECORD PAGE   DESCRIPTION
 00001 00001
 00002 00002	LET PASCAL(*,*,B,*) = {!PASCAL [INIT()] <BLOCK>!'.} MEAN
 00012 00003	EXPR GENCONDP(FLIST)
 00016 00004	EXPR FCN_ENTRYEXIT(L)
 00026 ENDMK
⊗;
LET PASCAL(*,*,B,*) = {!PASCAL [INIT()] <BLOCK>!'.} MEAN
	BEGIN
%B IS THE LIST <ENTRYCONDITION,EXITCONDITION,STATEMENT BODY>%
		TERPRI();
		PRINTSTR("PASCAL PROGRAM SUCCESSFULLY PARSED");
		GENCONDP(PROCEDURE_LIST);
		GENCONDM(B);
	END;
LET BLOCK(CR,PFD,*,CT) =
	{<CONDITION_RESULT>
	{REP 0 M *{{ALT <PROCEDURE_DECLARATION> |
	<DEFFUNDECL>|<VARIABLE_DECLARATION>}}}BEGIN <COMPOUND_TAIL>} MEAN
	BEGIN NEW X,Y;
	LOOP;	IF NULL PFD THEN RETURN CR@<CDR CT>;
		X←CAR PFD;
		PFD←CDR PFD;
		Y ← CDR X[1];
		IF X[1,1] = 1 THEN
			PROCEDURE_LIST←PROCEDURE_LIST@Y
		ELSE IF X[1,1]=2 THEN
			FUNCTION_LIST ← FUNCTION_LIST @ Y;
		GO LOOP
	END;
LET CONDITION_RESULT(PENTRY,*,EXIT,*) =
	{{OPT ENTRY <ASSERTION_EXPRESSION> '; } 
	EXIT <ASSERTION_EXPRESSION> '; }
	MEAN <IF PENTRY THEN PENTRY[2] ELSE 'TRUE, EXIT>;
LET PROCEDURE_DECLARATION(*,I,PL,*,B,*,*) =
	{PROCEDURE [IDENTIFIER] {OPT <PARAMETER_LIST>} '; 
	<PBLOCK> '; [FLUSH] } MEAN
	<I, PL,B>;
LET PBLOCK(CR,PFD,*,CT) =
	{<PCONDITION_RESULT>
	{REP 0 M *{{ALT <PROCEDURE_DECLARATION> |
	<DEFFUNDECL>|<VARIABLE_DECLARATION>}}}BEGIN <COMPOUND_TAIL>} MEAN
	BEGIN NEW X,Y;
	LOOP;	IF NULL PFD THEN RETURN CR@<CDR CT>;
		X←CAR PFD;
		PFD←CDR PFD;
		Y←CDR X[1];
		IF X[1,1]=1 THEN
			PROCEDURE_LIST←PROCEDURE_LIST@Y
		ELSE IF X[1,1]=2 THEN
			FUNCTION_LIST←FUNCTION_LIST@Y;
		GO LOOP
	END;
LET PCONDITION_RESULT(PENTRY,*,PEXIT,*)=
	{!ENTRY <INDEXED_ASSERT> '; 
	!EXIT <ASSERTION_EXPRESSION> '; }
	MEAN <PENTRY,PEXIT>;
LET DEFFUNDECL(*,I,PL,*,TY,*,CR,*)={DEFFUN [IDENTIFIER] <PARAMETER_LIST> 
	!': [IDENTIFIER] !'; <CONDITION_RESULT> [FLUSH]} MEAN<I,PL,CR,TY>;
LET VARIABLE_DECLARATION(*,TY) =
	{VAR{REP 1 M*{<IDENTIFIER_LIST> ': <PASCAL_TYPE> '; [FLUSH]
	}}} MEAN
	FOR NEW X IN TY DO
		IF CAR X[3,1] = 'ARRAY THEN
			FOR NEW Y IN X[1] DO
				ARRAY_LIST←(Y CONS CDR X[3])CONS ARRAY_LIST;
LET PARAMETER_LIST(*,S,*) = { '( 
	{REP 1 M *{{ALT<CONST_VAR_FCN_SPEC> |
	<PROCEDURE_SPEC>}}';} ') } MEAN
	BEGIN NEW SPEC, TYPE,J,X,Y,Z;
 	LOOP;	IF NULL S THEN RETURN J;
		X←CAR S;
		S←CDR S;
		SPEC ← X[1,2]; TYPE ← SPEC[3];
		Z←SPEC[2];
	LOOP1;	IF NULL Z THEN GO LOOP;
		Y←CAR Z;Z←CDR Z;
		J←J@<<Y,SPEC[1],TYPE>>;
		GO LOOP1
	END;
LET CONST_VAR_FCN_SPEC(S,IL,*,I) = {{OPT {ALT CONST | VAR | FUNCTION}}
	<IDENTIFIER_LIST> ': [IDENTIFIER]} MEAN
	IF NULL S THEN <'CONST, IL, I> ELSE <CADAR S, IL, I>;
LET PROCEDURE_SPEC(*,IL) = {PROCEDURE <IDENTIFIER_LIST>} MEAN
	<'PROCEDURE, IL, 'PROCEDURE>;
LET IDENTIFIER_LIST(I) = { {REP 1 M*{ [IDENTIFIER]}',}}
	MEAN I;
LET PASCAL_TYPE(KIND) = {{ALT ARRAY '[ <CONSTANT> '. '. <CONSTANT> '] OF
	[IDENTIFIER] | [IDENTIFIER]}} MEAN
	IF KIND[1] = 1 THEN <'ARRAY, KIND[4], KIND[7], KIND[10]>
	ELSE <'VARIABLE, KIND[2]>;
LET CONSTANT(KIND) = {{ALT [NUMBER] | [IDENTIFIER]}} MEAN CADR KIND;
LET COMPOUND_TAIL(S,*,*) = {
%Statements are orderd in reverse order%
	{REP 1 M *{{ALT [NUMBER]!': !<ASSERTION>|<STATEMENT>|<ASSERTION>}}';
	}!END  [FLUSH]} MEAN 
	BEGIN NEW J;
	FOR NEW X IN S DO
		IF X[1,1]=1 THEN LABEL_LIST←(X[1,2]CONS X[1,4,2])CONS LABEL_LIST
		ELSE IF X[1,2,1]='CMPD THEN J←CDR X[1,2]@J ELSE J←X[1,2]CONS J;
	J←'CMPD CONS J;
	RETURN J
	END;
LET STATEMENT(KIND) = {{OPT{ALT <ASSIGNMENT> | <COMPOUND> | <IF_STATEMENT> |
	<ASSERTION> | <WHILE_STATEMENT> | 
	<PROCEDURE_CALL> }}} MEAN IF KIND THEN CADAR KIND ELSE NIL;
LET ASSIGNMENT(V,*,E) = {<VARIABLE> {ALT '← | ': '=} <XPRESS>} MEAN 
	<'?←, V, E>;
LET COMPOUND(*,C) = {BEGIN <COMPOUND_TAIL>} MEAN C;
LET IF_STATEMENT(*,X1,*,S1,S2) = {IF <XPRESS> THEN <STATEMENT>
	{OPT ELSE <STATEMENT>}} MEAN 
	IF S2 THEN <'IFELSE, X1, S1, CADR S2>
	ELSE <'IF, X1, S1>;
LET INDEXED_ASSERT(ID,*,EX)={[IDENTIFIER] ': <ASSERTION_EXPRESSION>}
	MEAN	BEGIN NEW I;
		I←SHARPNAME(ID);
		RETURN I CONS SUBST(I,ID,EX)
		END;
LET ASSERTION(*,ASRT) = { ASSERT <ASSERTION_EXPRESSION> } MEAN
	<'ASRT, ASRT>;
LET WHILE_STATEMENT(*,X,*,EX,*,S) = {WHILE <XPRESS> '; <INDEXED_ASSERT> DO
	<STATEMENT>}
	MEAN <'WHILE, X, S,EX>;
LET PROCEDURE_CALL(I,*,XP,*) = { [IDENTIFIER] '( 
	{REP 1 M *{ <XPRESS> }',} ') } MEAN
	<'CALL,I,MAKECOMMAEXPR(FOR NEW X IN XP COLLECT X)>;
LET ASSERTION_EXPRESSION(AE1,AE) = { <XPRESS> {REP 0 M *{'& <XPRESS>}}}
	MEAN BEGIN NEW J;
	J ← AE1;
	FOR NEW X IN AE DO J ← <'?&, J, CADR X>;
	RETURN J;
	END;
LET XPRESS(RE,ORE) =
	{<RELATIONAL_EXPRESSION> {OPT {ALT '→ | '⊃} <RELATIONAL_EXPRESSION> }}
	MEAN IF ORE THEN <CADAR ORE, RE, CADR ORE> ELSE RE;
LET RELATIONAL_EXPRESSION(SE,OSE) = {<SIMPLE_EXPRESSION> {OPT 
	<RELATIONAL_OPERATOR> <SIMPLE_EXPRESSION>}} MEAN
	IF OSE THEN <CAR OSE, SE, CADR OSE> ELSE SE;
LET SIMPLE_EXPRESSION(A1,T1,TE) = { {OPT <ADDING_OPERATOR>} <TERM>
	{REP 0 M *{<ADDING_OPERATOR> <TERM>}}} MEAN
	BEGIN NEW J;
	IF A1 THEN J ← <CAR A1,T1> ELSE J ← T1;
	FOR NEW X IN TE DO J ← <CAR X, J, CADR X>;
	RETURN J;
	END;
LET TERM(F1,F) = {<FACTOR> {REP 0 M *{<MULT_OPERATOR> <FACTOR>}}} MEAN
	BEGIN NEW J;
	J ← F1;
	FOR NEW X IN F DO J ← <CAR X, J, CADR X>;
	RETURN J;
	END;
LET FACTOR(KIND) = {{ALT [IDENTIFIER] '( {REP 1 M*{<XPRESS>}',}')
	 | [NUMBER] | '( <XPRESS> ') |	'¬ <FACTOR> | <VARIABLE> |
	{ALT '∀ | '∃} {REP 1 M *{[IDENTIFIER]}',}
	'( <XPRESS> ') }}
	MEAN IF KIND[1] = 5 ∨ KIND[1] = 2 THEN KIND[2] ELSE
	IF KIND[1] = 3 THEN KIND[3] ELSE IF KIND[1] = 4 THEN
	<'?¬, KIND[3]> ELSE IF KIND[1] = 1 THEN
	<'FCN,KIND[2],MAKECOMMAEXPR(FOR NEW X IN KIND[4] COLLECT X)>
	ELSE
	BEGIN NEW J,K,L; K ← KIND[5];
	FOR NEW X IN KIND[3] DO BEGIN L←SHARPNAME(X[1]);J←IF J THEN<'?,,J,L>ELSE L;
	K←SUBST(L,X[1],K) END;RETURN <KIND[2,2], J, K>;
	END;
LET VARIABLE(I,SUB) = {[IDENTIFIER] {OPT '[ <XPRESS> '] }} MEAN
	IF SUB THEN <'ARRAY, I, SUB[2]> ELSE I;
LET RELATIONAL_OPERATOR(KIND) = {{ALT '= | '≠ | '< | '> | '≤ | '≥ }}
	MEAN CADR KIND;
LET ADDING_OPERATOR(KIND) = {{ALT '+ | '- | '∨}} MEAN CADR KIND;
LET MULT_OPERATOR(KIND) = {{ALT '* | '/ | '∧ | DIV | MOD}} MEAN
	CADR KIND;
%End of the Pascal syntax analyzer.%


EXPR GENCONDP(FLIST);
	PVCCOND←FOR NEW X IN FLIST COLLECT
		BEGIN NEW I;
			VCCOND←NIL;
			VCCOND←VCGEN(X[3,3],SUBST(<'?+,CAR X[3,1],1>,CAR X[3,1]
				,CDR X[3,1]),X[3,2])@VCCOND;
			VCCOND←VCGEN(OMEGASUBST(X[1],X[3,3]),SUBST(0,CAR X[3,1],CDR X[3,1]),
				X[3,2]);
			TERPRI();PRINT 'FOR;PRINC X[1];PRINT 'THE;PRINC LENGTH VCCOND;
			PRINTSTR(" THE VERIFICATION CONDITONS ARE:");
			I←1;
			IF NULL VCCOND THEN TERPRI() ALSO PRINT'VALID;
			<X[1]CONS(FOR NEW Y IN VCCOND COLLECT
				BEGIN   NEW RET;
					TERPRI();PRINT '?#;PRINC I;PRINC '? ;I←I+1;
					RET←APVC(Y);
					SHOW(12,RET);
					<RET>
				END)>
		END;

EXPR OMEGASUBST(I,A);
	IF ATOM A THEN A ELSE
	IF EQ(CAR A,'CALL)∧EQ(A[2],I) THEN '?π ELSE
	OMEGASUBST(I,CAR A)CONS OMEGASUBST(I,CDR A);

EXPR GENCONDM(B);
	BEGIN NEW I;
		VCCOND←NIL;
		VCCOND←VCGEN(B[3],B[1],B[2])@VCCOND;
		TERPRI();PRINTSTR("FOR THE MAIN PROGRAM");PRINC LENGTH VCCOND;
		PRINTSTR(" VERIFICATION CONDITIONS ARE:");
		I←1;
		IF NULL VCCOND THEN TERPRI() ALSO PRINT'VALID;
		MVCCOND←FOR NEW Y IN VCCOND COLLECT
			BEGIN   NEW RET;
				TERPRI();PRINT '?#;PRINC I;PRINC '? ;I←I+1;
				RET←APVC(Y);SHOW(12,RET);<RET>
			END
	END;
SPECIAL ASVAL,ARNAME,ARSUBS;
EXPR ARRAYSUBST(ASVAL,ARNAME,ARSUBS,S);
% ARNAME[ARSUBS]←ASVAL. Substitute for all occurrences of ARNAME in S. The 
newly created VC is returned as value.%
	IF NULL S THEN S ELSE
	IF ATOM S THEN S ELSE
	IF S[1]='ARRAY ∧S[2]=ARNAME THEN <'CONDEXP,<'?=,ARSUBS,S[3]>,ASVAL,
		<'ARRAY,S[2],ARRAYSUBST(ASVAL,ARNAME,ARSUBS,S[3])>> ELSE
	ARRAYSUBST(ASVAL,ARNAME,ARSUBS,S[1]) CONS ARRAYSUBST(ASVAL,ARNAME,
		ARSUBS,CDR S);


EXPR FCNLOCATE(XP, FCNNAMES);
%Append to the list FCNNAMES all function calls in the expression XP.
FCNNAMES contains elements in the form <function name, argument(s)>.%
	IF ATOM XP THEN FCNNAMES
	ELSE IF NULL CDDR XP THEN FCNNAMES @ FCNLOCATE(XP[2],NIL)
	ELSE IF XP[1] = 'FCN THEN FCNNAMES @ <CDR XP> @
		FCNLOCATE(XP[3], NIL)
	ELSE IF XP[1] = 'CONDEXP THEN FCNNAMES @ FCNLOCATE(XP[2], NIL)
		@ FCNLOCATE(XP[3], NIL) @ FCNLOCATE(XP[4], NIL)
	ELSE FCNNAMES @ FCNLOCATE(XP[2], NIL) @ FCNLOCATE(XP[3], NIL) ;

EXPR FCN_ENTRYEXIT(L);
%Given a list L in the form produced by FCNLOCATE, return <P, R> where 
P is the "anding" of the entry conditions (with actual parameters
substituted) for the functions in L, and where R is the "anding" of the
exit conditions.%
	BEGIN NEW FCN_INFO, QENTRY, PEXIT, POSITION, FORMAL,
	FCNNAME, FCNARGS,X;
	IF NULL L THEN RETURN NIL;
	X←CAR L;
	FCNNAME ← X[1]; FCNARGS ← DECOMMALIST(X[2]);
	FCN_INFO ← ASSOC(FCNNAME,FUNCTION_LIST);
	IF NULL FCN_INFO THEN PRINT FCNNAME
		ALSO PRINTSTR("NOT FOUND")
		ALSO QENTRY ← <'FCN, PRENAME(FCNNAME), X[2]>
		ALSO PEXIT ← <'FCN, RESNAME(FCNNAME), X[2]>
	ELSE BEGIN FCN_INFO←CDR FCN_INFO; QENTRY ← FCN_INFO[2,1];
		POSITION ← CONVCOMMA(FCN_INFO[1]);
		PEXIT ← ARGADD(FCNNAME,POSITION,FCN_INFO[2,2]);
		FORMAL←DECOMMALIST(POSITION);
		QENTRY←PARSUBST(FCNARGS,FORMAL,QENTRY);
		PEXIT←PARSUBST(FCNARGS,FORMAL,PEXIT);
		END;
	RETURN <QENTRY,PEXIT>CONS FCN_ENTRYEXIT(CDR L)
	END;

EXPR IDSUBST(EX,ID,VC);
	IF ATOM VC THEN(IF VC=ID THEN EX ELSE VC)ELSE
	IF CAR VC='FCN THEN<VC[1],VC[2],IDSUBST(EX,ID,VC[3])>ELSE
		CONS(IDSUBST(EX,ID,CAR VC),IDSUBST(EX,ID,CDR VC));

EXPR ARGADD(ID,PL,VC);
	IF ATOM VC THEN(IF VC=ID THEN<'FCN,ID,PL>ELSE VC)ELSE
	IF CAR VC='FCN THEN<VC[1],VC[2],ARGADD(ID,PL,VC[3])>ELSE
		CONS(ARGADD(ID,PL,CAR VC),ARGADD(ID,PL,CDR VC));

EXPR PARSUBST(ACTUAL,FORMAL,VC);
	IF ATOM VC THEN
		BEGIN
			NEW X,Y;
			X←ACTUAL;Y←FORMAL;
	   	A;	IF NULL X THEN RETURN VC ELSE
			IF NULL Y THEN TERPRI()
				ALSO RETURN NIL ELSE
			IF CAR Y=VC THEN RETURN CAR X ELSE
				Y←CDR Y ALSO X←CDR X
				ALSO GO A
		END ELSE
	IF LENGTH VC=2 THEN <VC[1],PARSUBST(ACTUAL,FORMAL,VC[2])>ELSE
	IF LENGTH VC=3 THEN <VC[1],PARSUBST(ACTUAL,FORMAL,VC[2]),PARSUBST
		(ACTUAL,FORMAL,VC[3])> ELSE <VC[1],PARSUBST(ACTUAL,FORMAL,
	VC[2]),PARSUBST(ACTUAL,FORMAL,VC[3]),PARSUBST(ACTUAL,FORMAL,VC[4])>;

EXPR DECOMMALIST(L);
%Given a comma-expression representing a list of expressions, produce
a list of the individual expressions.%
	IF ATOM L ∨ L[1] ≠ '?, THEN <L> ELSE
		DECOMMALIST(L[2]) @ <L[3]> ;

EXPR MAKECOMMAEXPR(L);
%Given a list of expresssions produce a single comma-expression of the
list elements.%
	BEGIN NEW ARGSEXPR;
	ARGSEXPR ← L[1];
	FOR NEW X IN CDR L DO ARGSEXPR ← <'?,, ARGSEXPR, X>;
	RETURN ARGSEXPR;
	END;

EXPR FCNCONDITIONS(E);
%If there are no function calls in E, then return NIL else return the
<P, R> from FCN_ENTRYEXIT.%
	FCN_ENTRYEXIT(FCNLOCATE(E,NIL));

EXPR SHARPNAME(ID);
%From the identifier ID produce the next name of the form ID#123.  The
suffixed integer is determined by the property list BOUND_VARIABLES.
The property is the identifier and the value on entry is the last used
counter value for that identifier.  Absence of the property means no
previous use; ID#0 becomes ID#  without the zero.%
	BEGIN NEW COUNTER,PAIR;
	PAIR ← ASSOC(ID,BOUND_VARIABLES);
	IF NULL PAIR THEN PAIR ← ID CONS 0 ALSO 
		BOUND_VARIABLES ← PAIR CONS BOUND_VARIABLES;
	RPLACD(PAIR,(CDR PAIR)+1);
	COUNTER ← INTERN MAKNAM (EXPLODE ID @ <'??, '?#> @
		EXPLODE CDR PAIR);
	RETURN COUNTER;
	END;

EXPR PRENAME(ID);
%From the identifier ID produce PRE_ID, i.e. same name with PRE_ prefixed.%
	INTERN MAKNAM(EXPLODE 'PRE @ <'??, '?_> @ EXPLODE ID);

EXPR RESNAME(ID);
%From the identifier ID produce RES_id, i.e. same name with RES_ prefixed.%
	INTERN MAKNAM(EXPLODE 'RES @ <'??, '?_> @ EXPLODE ID);

EXPR TABLE();
%Set up property list of hierarchies of the operators.%
	BEGIN
	PUTPROP('HIERARCHY,  9, '?&);
	PUTPROP('HIERARCHY, 10, '?→);
	PUTPROP('HIERARCHY, 10, '?⊃);
	PUTPROP('HIERARCHY,  9, '?,);
	FOR NEW X IN <'?=, '?≠, '?<, '?>, '?≤, '?≥> DO
		PUTPROP('HIERARCHY, 8, X);
	FOR NEW X IN <'?+, '?-, '?∨> DO
		PUTPROP('HIERARCHY, 6, X);
	FOR NEW X IN <'?*, '?/, '?∧, 'DIV, 'MOD> DO
		PUTPROP('HIERARCHY, 4, X);
	PUTPROP('HIERARCHY,  2, '?¬);
	END;

EXPR SHOW(PREC, FORMULA);
%Display expression FORMULA "after" an operator of precedence PREC.%
	IF ATOM FORMULA THEN PRINC FORMULA
	ELSE IF NULL CDDR FORMULA THEN
		PRINC FORMULA[1] ALSO SHOW(2,FORMULA[2])
	ELSE IF FORMULA[1] = 'FCN THEN
		PRINC FORMULA[2] ALSO PRINC '?(
		ALSO SHOW(12, FORMULA[3]) ALSO PRINC '?)
	ELSE IF FORMULA[1] = 'ARRAY THEN
		PRINC FORMULA[2] ALSO PRINC '?[
		ALSO SHOW(12, FORMULA[3]) ALSO PRINC '?]
	ELSE IF FORMULA[1] = 'CONDEXP THEN
		PRINC '?( ALSO PRINC '? IF?  ALSO SHOW(12, FORMULA[2])
		ALSO PRINC '? THEN?  ALSO SHOW(12, FORMULA[3])
		ALSO PRINC '? ELSE?  ALSO SHOW(12, FORMULA[4])
		ALSO PRINC '?)
	ELSE IF FORMULA[1] = '?∀ ∨ FORMULA[1] = '?∃ THEN
		PRINC FORMULA[1] ALSO SHOW(12, FORMULA[2])
		ALSO PRINC '?( ALSO SHOW(12, FORMULA[3])
		ALSO PRINC '?)
	ELSE BEGIN NEW HIER, OP, DIVMOD, LEFT;
		OP ← FORMULA[1]; DIVMOD ← OP = 'DIV ∨ OP = 'MOD;
		HIER ← GET('HIERARCHY, OP);
		LEFT ← (PREC LESSP HIER)∨OP='?→∨OP='?⊃∨OP='?-∨OP='?/∨DIVMOD;
		IF LEFT THEN PRINC '?(;
		SHOW(HIER,FORMULA[2]);
		IF DIVMOD THEN PRINC '?  ALSO PRINC OP ALSO PRINC '? 
			ELSE PRINC OP;
		SHOW(HIER,FORMULA[3]); 
		IF LEFT THEN PRINC '?);
	END;

FEXPR SAVEVC (FLIST);
	BEGIN
	NEW DEV;
	DEV ← 'DSK?:;
LOOP; 	IF NULL FLIST THEN RETURN 'FINISHED
	ELSE IF CAR LAST EXPLODE CAR FLIST EQ '?: 
		| ¬ATOM CAR FLIST & ¬ATOM CDAR FLIST
		THEN DEV ← CAR FLIST
		ALSO FLIST ← CDR FLIST
		ALSO GO LOOP;
	EVAL <'OUTPUT, 'DSK?:, (
		IF ATOM CAR FLIST THEN CAR FLIST
		ELSE FLIST[1,1]) CONS 'VC>;
	OUTC(T, NIL);
	EVAL <FUNCTION PARSE, DEV, CAR FLIST>;
	OUTC(NIL, T);
        PRINTSTR ("FILE CREATED: " CAT (IF ATOM CAR FLIST THEN CAR FLIST
		ELSE FLIST[1,1])CAT ".VC") ;
	FLIST ← CDR FLIST;
	GO LOOP;
	END;

LET PROGRAM(*) = {<PASCAL>} MEAN NIL;

_EOF_